#ifndef __SILZ_ASTAR_H__
#define __SILZ_ASTAR_H__
//#pragma once

#include <vector>
#include <algorithm>
#include <cmath>
#include "cocos2d.h"

#define STRAIGHT_COST 1.0
#define DIAG_COST M_SQRT2

struct ASNode;
class GameMap;

struct ASNodeLink
{
    ASNodeLink(ASNode *node, double cost)
        :node(node)
        ,cost(cost)
    {
    }
    ASNode *node;
    double cost;
};

struct ASNode
{
	ASNode(int x, int y)
		:x(x)
		,y(y)
		,f(0.0)
		,g(0.0)
		,h(0.0)
		,walkable(false)
		,parent(nullptr)
		,version(1)
		,links()
	{
	}
	int x;
	int y;
	double f;
	double g;
	double h;
	ASNode *parent;
	bool walkable;
	int version;
	std::vector<ASNodeLink*> links;
	
};

class ASGrid
{
public:
	ASGrid(int cols, int rows);
	~ASGrid();
	void calculateLinks();
	void setEndNode(int col, int row);
	void setStartNode(int col, int row);
	void setWalkable(int col, int row, bool value);
	ASNode* getNode(int col, int row);
	ASNode* getEndNode() { return _pEndNode; }
	ASNode* getStartNode() { return _pStartNode; }
	int getNumCols() { return _nNumCols; }
	int getNumRows() { return _nNumRows; }

private:
	void initNodeLink(ASNode *node);

private:
	ASNode *_pStartNode;
	ASNode *_pEndNode;
	int _nNumCols;
	int _nNumRows;
	std::vector<ASNode*> _vNodes;
};

class AStar
{
public:
	AStar(ASGrid *grid);
    bool findPath();
    void floyd();
    bool search();
    
    const std::vector<ASNode*>& getPath() { return _path; }
    const std::vector<ASNode*>& getFloyPath() { return _floydPath; }

    static bool justMin(ASNode *n1, ASNode *n2);
    
private:
    bool floydCrossAble(const ASNode &n1, const ASNode &n2);
    void bresenhamNodes(std::vector<cocos2d::Point> &result, cocos2d::Point &p1, cocos2d::Point &p2); 
    void floydNode(ASNode &result, const ASNode &n1, const ASNode &n2);
    void buildPath();
    double euclidian(const ASNode &node);

private:
    std::vector<ASNode*> _open;
    std::vector<ASNode*> _path;
    std::vector<ASNode*> _floydPath;
    ASGrid *_grid;
    ASNode *_endNode;
    ASNode *_startNode;
    int _nowVersion;

};


class SilzAstar
{
public:
    SilzAstar();
    ~SilzAstar();
    void makeGrid(const GameMap *map);
	void find(std::vector<cocos2d::Point> &result, float srcX, float srcY, float descX, float descY);

private:
    ASGrid *_grid;
    AStar *_astar;
};

#endif